﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BitTorrent.Agents;
using BitTorrent.Client.Peer;
using BitTorrent.Client.Tracker;
using Microsoft.Ccr.Core;

namespace BitTorrent.Client {
    internal class Infrastructure {
        private readonly HttpTrackerAgent _trackerAgent;
        private readonly DispatcherQueue _dispatcherQueue;
        private readonly Port<IPeer> _peerPort = new Port<IPeer>();
        private readonly Port<Exception> _errorPort;

        public Infrastructure(File.MetaFile metaFile, DispatcherQueue dispatcherQueue, Port<Exception> errorPort) {
            _dispatcherQueue = dispatcherQueue;
            _errorPort = errorPort;

            var request = new HttpTrackerRequest {
                                                     AnnounceUri = metaFile.Announce.First().First(),
                                                     Compact = true,
                                                     Downloaded = 0,
                                                     InfoHash = metaFile.Info.GetHash(),
                                                     Left = (metaFile.Info.PieceLength*metaFile.Info.Pieces.Count()),
                                                     NumberOfPeers = 20,
                                                     PeerId = new PeerId(),
                                                     Port = 6889,
                                                     RequestEvent = HttpTrackerRequestType.Started,
                                                     Uploaded = 0
                                                 };
                                                                
            
            

            _trackerAgent = new HttpTrackerAgent(request, _dispatcherQueue, PeerPort, _errorPort);
            _trackerAgent.Announce();
        }

        public Port<IPeer> PeerPort {
            get { return _peerPort; }
        }

        public PortSet<Downloaded, Uploaded> TrackerPort {
            get { return _trackerAgent.Port; }
        }
    }

    internal class TorrentAgent : AgentBase {
        private Infrastructure _infrastructure;

        public TorrentAgent(File.MetaFile metaFile, Dispatcher dispatcher)
            : base(new DispatcherQueue("TorrentAgent", dispatcher)) {
            _infrastructure = new Infrastructure(metaFile, TaskQueue, new Port<Exception>());
        }
    }

    internal class PeerDispatcherAgent : AgentBase {
        List<PeerAgent> _peers = new List<PeerAgent>();

        protected PeerDispatcherAgent(DispatcherQueue dispatcherQueue) : base(dispatcherQueue) {
            Port = new Port<IPeer>();
            Activate(
                Arbiter.Interleave(
                    // ---------------------------------------------------------------------------------------
                    new TeardownReceiverGroup(Cleanup(s => {
                                                          // TODO (fen): Implement Teardown for PeerDispatcherAgent
                                                      })),
                    // ---------------------------------------------------------------------------------------
                    new ExclusiveReceiverGroup(Arbiter.Receive(true, Port, PeerHandler)),
                    // ---------------------------------------------------------------------------------------
                    new ConcurrentReceiverGroup()
                    ));
        }

        private void PeerHandler(IPeer message) {
            var peerAgent = new PeerAgent(message, TaskQueue);
            _peers.Add(peerAgent);
        }

        public Port<IPeer> Port { get; private set; }
    }
}
